﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SmartMathLibrary
{
    /// <summary>
    /// This class represents a mathematical inverse matrix.
    /// </summary>
    [Serializable]
    public class InverseMatrix : Matrix, IInverseMatrix
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="InverseMatrix"/> class.
        /// </summary>
        /// <param name="dimension">The dimension of the matrix.</param>
        public InverseMatrix(int dimension)
            : base(dimension, dimension)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="InverseMatrix"/> class.
        /// </summary>
        /// <param name="matrix">The matrix to clone.</param>
        public InverseMatrix(InverseMatrix matrix)
            : base(matrix.Rows, matrix.Columns)
        {
            if (matrix == (InverseMatrix) null)
            {
                throw new ArgumentNullException("matrix");
            }

            for (int i = 0; i < this.Rows; i++)
            {
                for (int j = 0; j < this.Columns; j++)
                {
                    this.SetValueAtPosition(new MatrixPosition(i, j),
                                            matrix.GetValueAtPosition(new MatrixPosition(i, j)));
                }
            }
        }

        /// <summary>
        /// Creates the inverse matrix of a matrix.
        /// </summary>
        /// <param name="matrix">The matrix from which the inverse matrix should be
        /// calculated.</param>
        /// <returns>The calculated inverse matrix of the matrix.</returns>
        public static InverseMatrix FromMatrix(SquareMatrix matrix)
        {
            if (matrix.Rows != matrix.Columns)
            {
                throw new ArgumentException("The specified matrix has to be a square matrix.");
            }

            if (matrix == (Matrix) null)
            {
                throw new ArgumentNullException("matrix");
            }

            Matrix tempuri = Matrix.AppendIdentityMatrix(matrix);
            InverseMatrix result = new InverseMatrix(tempuri.Rows);

            tempuri.CreateUpperTriangularMatrix();
            tempuri.CreateDiagonalMatrix();
            tempuri.CreateIdentityMatrix();

            for (int i = 0; i < tempuri.Rows; i++)
            {
                for (int j = tempuri.Rows; j < tempuri.Columns; j++)
                {
                    result.SetValueAtPosition(new MatrixPosition(i, j - tempuri.Rows),
                                              tempuri.GetValueAtPosition(new MatrixPosition(i, j)));
                }
            }

            return result;
        }
    }
}